---
title: Objects
description: Guide for defining Object types in Pothos
---

This will walk you through creating your first object types, some concepts in this guide will be
explained further in later guides.

### Defining an Object type

When adding a new type to your schema, you'll need to figure how the data behind this type will be
represented. Pothos entirely decouples your data from your GraphQL schema, and has many different
ways to implement Objects in your schema.

In this guide, we will be implementing a `Giraffe` object type:

```typescript
interface Giraffe {
  name: string;
  birthday: Date;
  heightInMeters: number;
}
```

The easiest way to create a new Object based in an existing Typescript type is with the `objectRef`
method:

```typescript
const builder = new SchemaBuilder({});
const GiraffeRef = builder.objectRef<Giraffe>('Giraffe');
```

This will create a new `ObjectRef` that can be used to reference the `Giraffe` type in other parts
of the schema. By passing in the Giraffe interface, We give the `ObjectRef` the information it needs
to ensure that fields we add to the Giraffe type are type-safe, and that any fields that reference
the Giraffe Field return the expected data.

Next, we can add an implementation for the `Giraffe` type:

```typescript
const GiraffeRef = builder.objectRef<Giraffe>('Giraffe');

GiraffeRef.implement({
  description: 'Long necks, cool patterns, taller than you.',
  fields: (t) => ({}),
});
```

In the implementation, we can add a description (optional) and a function to define the fields
available to query on the Giraffe type.

### Add some fields

The `fields` function receives a `FieldBuilder` instance that can be used to define the fields for
your type. the `FieldBuilder` will be covered in more details in the [fields guide](./fields).

```typescript
GiraffeRef.implement(Giraffe, {
  fields: (t) => ({
    name: t.exposeString('name'),
    height: t.exposeFloat('heightInMeters'),
    age: t.int({
      resolve: (parent) => {
        // Do some date math to get an approximate age from a birthday
        const ageDifMs = Date.now() - parent.birthday.getTime();
        const ageDate = new Date(ageDifMs); // milliseconds from epoch
        return Math.abs(ageDate.getUTCFullYear() - 1970);
      },
    }),
  }),
});
```

You'll notice that we haven't added any additional typescript definitions when defining our fields.
Pothos will uses the type provided to `objectRef` to ensure that the fields we add to the Giraffe
type are type-safe. This type is only used to ensure that the implementation is type-safe, but
Pothos we never automatically expose properties from the underlying data without an explicit field
definition.

In the example above, we have examples of "exposing" data from the underlying type, ad well as field
that requires some additional logic to resolve.

## Add a query

We can create a root `Query` object with a field that returns a giraffe using `builder.queryType`

```typescript
builder.queryType({
  fields: (t) => ({
    giraffe: t.field({
      type: GiraffeRef,
      resolve: () => ({
        name: 'James',
        birthday: new Date(Date.UTC(2012, 11, 12)),
        heightInMeters: 5.2,
      }),
    }),
  }),
});
```

We can use the `ObjectRef` created earlier as the `type` option when defining fields that return the
Giraffe type.

### Create a server

Pothos schemas build into a plain schema that uses types from the `graphql` package. This means it
should be compatible with most of the popular GraphQL server implementations for node. In this guide
we will use `graphql-yoga` but you can use whatever server you want.

```typescript
import { createServer } from 'http';
import { createYoga } from 'graphql-yoga';

const yoga = createYoga({
  schema: builder.toSchema(),
  context: (ctx) => ({
    user: { id: Number.parseInt(ctx.request.headers.get('x-user-id') ?? '1', 10) },
  }),
});

export const server = createServer(yoga);
server.listen(3000);
```

### Query your data

1. Run your server (either with `ts-node`) by compiling your code and running it with node.
2. Open [http://0.0.0.0:3000/graphql](http://0.0.0.0:3000/graphql) to open the playground and query
   your API:

```graphql
query {
  giraffe {
    name
    age
    height
  }
}
```

## Different ways to define Object types

There are many different ways that you can provide type information to Pothos about what the
underlying data in your graph will be. Depending on how the rest of your application is structured
you can pick the approach that works best for you, or use a combination of different styles.

### Using Refs

ObjectRefs (the method shown above) is the most flexible solution, and makes it easy to integrate
pothos with data sources that have their own Typescript types.

Object refs can be created using `builder.objectRef`, and then implemented by calling the
`implement` method on the ref, or by passing the ref to `builder.objectType`:

```typescript
const GiraffeRef = builder.objectRef<GiraffeType>('Giraffe').implement({
  description: 'Long necks, cool patterns, taller than you.',
  fields: (t) => ({}),
});
```

import { Callout } from 'fumadocs-ui/components/callout';

<Callout type="warn">
  When using objectRefs with circular dependencies, ensure that the `implement` method is called as
  a separate statement, or typescript may complain about circular references:
</Callout>

### Using classes

If your data is already represented as a class, Pothos supports using the classes themselves as
ObjectRefs. This allows you to define a type-safe schema with minimal typescript definitions.

```typescript
export class Giraffe {
  name: string;
  birthday: Date;
  heightInMeters: number;

  constructor(name: string, birthday: Date, heightInMeters: number) {
    this.name = name;
    this.birthday = birthday;
    this.heightInMeters = heightInMeters;
  }
}

builder.objectType(Giraffe, {
  // Name is required when using a class as an ObjectRef
  name: 'Giraffe',
  description: 'Long necks, cool patterns, taller than you.',
  fields: (t) => ({}),
});

builder.queryFields((t) => ({
  giraffe: t.field({
    type: Giraffe,
    resolve: () => new Giraffe('James', new Date(Date.UTC(2012, 11, 12)), 5.2),
  }),
}));
```

### Using SchemaTypes

You can also provide type mappings when you create the [SchemaBuilder](./schema-builder), which
allows you to reference the types by name throughout your schema (as a string).

```typescript
const builder = new SchemaBuilder<{ Objects: { Giraffe: GiraffeType } }>({});

builder.objectType('Giraffe', {
  description: 'Long necks, cool patterns, taller than you.',
  fields: (t) => ({}),
});

builder.queryFields((t) => ({
  giraffe: t.field({
    type: 'Giraffe',
    resolve: () => ({
      name: 'James',
      birthday: new Date(Date.UTC(2012, 11, 12)),
      heightInMeters: 5.2,
    }),
  }),
}));
```

This is ideal when you want to list out all the types for your schema in one place, or you have
interfaces/types that define your data rather than classes, and means you won't have to import
anything when referencing the object type in other parts of the schema.

The type signature for [SchemaBuilder](../api/schema-builder) is described in more detail
[later](../api/schema-builder), for now, it is enough to know that the `Objects` type provided to
the schema builder allows you to map the names of object types to type definitions that describe the
data for those types.
